package concat

import (
	"crypto/md5"
	"fmt"
	"io/ioutil"
	"mime"
	"os"
	"path"
	"strings"
)

const (
	DefaultDirMode  = 0755
	DefaultFileMode = 0644
	DefaultMimeType = "application/x-javascript; charset=utf-8"
)

// 追加元素到列表中，保持元素唯一性
func appendIfMissing(slice []string, s string) []string {
	for _, v := range slice {
		if s == v {
			return slice
		}
	}
	return append(slice, s)
}

// 判断文件是否存在
func FileExist(filepath string) bool {
	if _, err := os.Stat(filepath); err != nil || err == os.ErrNotExist {
		return false
	}
	return true
}

// 获取文件的MIME类型
// 首先获取文件的扩展名，根据扩展名查询MIME类型
func TypeByFileName(filename string) string {
	if pos := strings.LastIndex(filename, "."); pos > -1 {
		return mime.TypeByExtension(filename[pos:])
	}
	return ""
}

// 批量获取文件类型，不重复添加MIME类型
func mimeTypes(filenames []string) (types []string) {
	for _, filename := range filenames {
		if mimeType := TypeByFileName(filename); mimeType != "" {
			types = appendIfMissing(types, mimeType)
		}
	}
	return
}

// 获取MIME类型
func MIMEType(rawFileName, sep string) string {
	mimeTypes := mimeTypes(ParseFileName(rawFileName, sep, false))
	if len(mimeTypes) == 1 {
		return mimeTypes[0]
	}
	return DefaultMimeType
}

// 解析文件名
func ParseFileName(rawFileName, sep string, compatible bool) []string {
	var filenames []string
	for _, filename := range strings.Split(rawFileName, sep) {
		if compatible {
			filename = ReplaceFileName(filename)
		}
		filenames = appendIfMissing(filenames, filename)
	}
	return filenames
}

// 实现路径转换，比如style.abc.css替换成style/abc.css
func ReplaceFileName(filename string) string {
	if count := strings.Count(filename, "."); count > 1 {
		return strings.Replace(filename, ".", "/", count-1)
	}
	return filename
}

// 组合文件路径
// 返回存在的文件路径
func GetFilePath(staticPath string, filenames []string) []string {
	var filepaths []string
	for _, filename := range filenames {
		filepath := path.Join(staticPath, filename)
		if FileExist(filepath) {
			filepaths = append(filepaths, filepath)
		}
	}
	return filepaths
}

// 阅读整个文件，不会有io.EOF的错误
func ReadFile(filepath string) ([]byte, error) {
	return ioutil.ReadFile(filepath)
}

// 写入文件
func WriteFile(filepath string, data []byte) error {
	return ioutil.WriteFile(filepath, data, DefaultFileMode)
}

// 递归创建目录
// 类似shell的mkdir -p
func MkdirAll(path string) error {
	return os.MkdirAll(path, DefaultDirMode)
}

// md5
func Md5(key []byte) string {
	h := md5.New()
	h.Write(key)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func init() {
	// 修复.js类型为application/x-javascript
	mime.AddExtensionType(".js", DefaultMimeType)
}
